前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket

# Session 与 Token

30 秒速记

  • 都是解决 HTTP 无状态下「你是谁」的问题,区别在状态存哪
  • Session:状态存服务端,客户端只拿一个随机的 session id(通常放 Cookie);好撤销,但要共享存储
  • Token(常见 JWT):用户信息签名后交给客户端,服务端验签就行,不用查库;好扩展,但难主动作废
  • JWT 只是签名不是加密,payload 谁都能 base64 解出来,别放敏感信息
  • 实践:短期 access token + 长期 refresh token;不管哪种都要 HTTPS,并防好 XSS / CSRF

Session 和 Token 都是用来记住登录状态的,区别在于状态存在哪:Session 存在服务端,Token 把信息签好名交给客户端自己带着。 Session 的做法是登录后服务端生成一个随机 id,把用户信息存在内存或 Redis 里,浏览器只拿这个 id,所以想踢人下线删掉记录就行,代价是多台服务器要共享存储。Token 比如 JWT,用户 id、过期时间直接写进去再签名,服务端只验签不查库,天然适合多服务、跨域和 App,但签发出去就很难提前作废。所以实际项目里常配短有效期的 access token 加 refresh token。

理解「Session 与 Token」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 security 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

HTTP 本身不记得你是谁,每个请求都是独立的,所以需要一种机制在请求之间维持登录状态。Session 和 Token 是两种主流思路。

Session 是「服务端记账」。用 express-session 写起来是这样:

const session = require('express-session');
app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  cookie: { httpOnly: true, secure: true, sameSite: 'lax', maxAge: 2 * 3600 * 1000 },
  // 多实例部署时加 store: new RedisStore({ client: redisClient })
}));

app.post('/login', (req, res) => {
  req.session.userId = 42;  // 数据存在服务端,浏览器只拿到一个 connect.sid
  res.json({ ok: true });
});
app.post('/logout', (req, res) => req.session.destroy(() => res.json({ ok: true })));
@前端进阶之旅: 代码已经复制到剪贴板

Token 是「客户端带证件」。以 JWT 为例,它由 header.payload.signature 三段组成:

const jwt = require('jsonwebtoken');
const token = jwt.sign({ uid: 42 }, process.env.JWT_SECRET, { expiresIn: '15m' });
// 客户端之后在请求头里带上 Authorization: Bearer <token>

const payload = jwt.verify(token, process.env.JWT_SECRET); // { uid: 42, iat, exp }
// 签名不对或已过期会直接抛错
@前端进阶之旅: 代码已经复制到剪贴板

怎么选:传统的服务端渲染网站、需要随时踢人下线的后台,Session 简单可靠;多个服务共用登录态、要给 App 和第三方用的接口,Token 更方便。两种方案不是非此即彼,很多系统是 Session 管网页登录、Token 管开放接口。

面试官追问

追问 1JWT 里能放用户手机号吗?
参考回答

别放。JWT 的 payload 只是 base64url 编码,复制到 jwt.io 就能看到原文,签名只保证内容没被改,不保证别人看不到。只放用户 id、角色、过期时间这类必要字段。

追问 2用户改了密码,之前签发的 JWT 怎么让它失效?
参考回答

JWT 本身做不到,得加点状态:用户表存一个 tokenVersion,签发时写进 token,校验时对比,改密码就把版本号加一;或者把要作废的 jti 放进 Redis 黑名单直到它过期。

追问 3Token 存 localStorage 还是 Cookie?
参考回答

localStorage 怕 XSS,脚本一跑就能读走;HttpOnly 的 Cookie 脚本读不到,但会自动带上,要防 CSRF,配 SameSite=Lax 基本够用。我更倾向 HttpOnly 加 Secure 加 SameSite 的 Cookie。

追问 4服务从一台扩到三台,用 Session 的登录老是掉,怎么办?
参考回答

Session 存在各自进程内存里,请求分到别的机器就查不到。把 Session 存到 Redis,比如 express-session 配 connect-redis,三台机器读同一份。

追问 5用了 JWT 是不是就不用查数据库了?
参考回答

验身份可以不查,但权限别全信 token 里的角色。用户被封禁或者降权后,旧 token 里的角色还是老的,敏感操作要再查一次当前状态。

# Session

30 秒速记

  • Session = 服务端给每个用户建一份档案,浏览器只拿一个编号(session id),下次来凭编号查档案
  • 编号一般放 Cookie 自动带上;Cookie 是载体,Session 是服务端的存储,两者配合不是二选一
  • session id 要随机不可猜,登录成功后要换一个新的,防会话固定攻击
  • 默认存进程内存,重启就丢、多实例不共享 → 线上存 Redis
  • 「不能跨域」说的是 Cookie 受域名限制:子域共享靠 Domain,跨站要 credentials + SameSite=None; Secure + 后端允许凭证

Session 就是服务端给每个登录用户建的一份档案,浏览器手里只拿一个编号,每次请求带着编号来,服务端按编号把档案翻出来。 编号通常放在 Cookie 里,所以 Cookie 是载体、Session 是服务端那份数据,两者是配合关系。好处是用户信息不出服务器,想让谁下线直接删档案。坑主要在存储:默认存进程内存,服务一重启或者扩成多实例,档案就找不到了,所以线上都存 Redis。常说的「Session 不能跨域」,本质是装编号的 Cookie 有域名限制,配好 CORS 凭证和 SameSite 是能带过去的。

Session 是一种记录客户状态的机制,不同的是 Cookie 保存在客户端浏览器中,而 Session 保存在服务器上的进程中。

客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上,这就是 Session。客户端浏览器再次访问时只需要从该 Session 中查找该客户的状态就可以了。

如果说 Cookie 机制是通过检查客户身上的“通行证”来确定客户身份的话,那么 Session 机制就是通过检查服务器上的“客户明细表”来确认客户身份。

Session 相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。

Session 不能跨域

面试官追问

追问 1把完整用户信息放进 Cookie,服务端什么都不存,这算 Session 吗?
参考回答

不算,这是纯 Cookie 方案。没签名的话用户改一下 Cookie 就能冒充别人。Session 的要点是数据在服务端,客户端只有一个查档案用的随机 id。

追问 2登录成功后为什么要重新生成 session id?
参考回答

防会话固定攻击:攻击者先拿到一个 id 塞给你,你用它登录后,他手里的 id 也成了登录态。express-session 里登录成功调一次 req.session.regenerate()。

追问 3运营后台在 admin.a.com,接口在 api.a.com,请求总是拿不到 Session,怎么办?
参考回答

前端请求要带 credentials: 'include',后端返回 Access-Control-Allow-Credentials: true,并且 Allow-Origin 写具体域名不能写 *。两个子域同站,Cookie 设 Domain=.a.com 就能共享。

追问 4管理员要求能立刻把某个用户踢下线,Session 怎么做?
参考回答

在 Redis 里按用户 id 维护一个他的 session id 列表,踢人时把这些 Session 全删了,用户下次请求就查不到档案,自然掉线。

追问 5用户量很大,Session 存储会不会扛不住?
参考回答

一个 Session 一般就几百字节,百万在线也就几百 MB,Redis 完全扛得住。关键是设置合理的过期时间,别把大对象塞进 Session,存个用户 id 就够了,详细信息用时再查。

#

基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
      • Session
        • Session 与 Cookie 的区别
        • Session 应用
      • Token
    • Cookie、Session、Token、JWT
    • Socket
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

Session 与 Token|Nodejs专题系列

# Session 与 Token

30 秒速记

  • 都是解决 HTTP 无状态下「你是谁」的问题,区别在状态存哪
  • Session:状态存服务端,客户端只拿一个随机的 session id(通常放 Cookie);好撤销,但要共享存储
  • Token(常见 JWT):用户信息签名后交给客户端,服务端验签就行,不用查库;好扩展,但难主动作废
  • JWT 只是签名不是加密,payload 谁都能 base64 解出来,别放敏感信息
  • 实践:短期 access token + 长期 refresh token;不管哪种都要 HTTPS,并防好 XSS / CSRF

Session 和 Token 都是用来记住登录状态的,区别在于状态存在哪:Session 存在服务端,Token 把信息签好名交给客户端自己带着。 Session 的做法是登录后服务端生成一个随机 id,把用户信息存在内存或 Redis 里,浏览器只拿这个 id,所以想踢人下线删掉记录就行,代价是多台服务器要共享存储。Token 比如 JWT,用户 id、过期时间直接写进去再签名,服务端只验签不查库,天然适合多服务、跨域和 App,但签发出去就很难提前作废。所以实际项目里常配短有效期的 access token 加 refresh token。

理解「Session 与 Token」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 security 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

HTTP 本身不记得你是谁,每个请求都是独立的,所以需要一种机制在请求之间维持登录状态。Session 和 Token 是两种主流思路。

Session 是「服务端记账」。用 express-session 写起来是这样:

const session = require('express-session');
app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  cookie: { httpOnly: true, secure: true, sameSite: 'lax', maxAge: 2 * 3600 * 1000 },
  // 多实例部署时加 store: new RedisStore({ client: redisClient })
}));

app.post('/login', (req, res) => {
  req.session.userId = 42;  // 数据存在服务端,浏览器只拿到一个 connect.sid
  res.json({ ok: true });
});
app.post('/logout', (req, res) => req.session.destroy(() => res.json({ ok: true })));
@前端进阶之旅: 代码已经复制到剪贴板

Token 是「客户端带证件」。以 JWT 为例,它由 header.payload.signature 三段组成:

const jwt = require('jsonwebtoken');
const token = jwt.sign({ uid: 42 }, process.env.JWT_SECRET, { expiresIn: '15m' });
// 客户端之后在请求头里带上 Authorization: Bearer <token>

const payload = jwt.verify(token, process.env.JWT_SECRET); // { uid: 42, iat, exp }
// 签名不对或已过期会直接抛错
@前端进阶之旅: 代码已经复制到剪贴板

怎么选:传统的服务端渲染网站、需要随时踢人下线的后台,Session 简单可靠;多个服务共用登录态、要给 App 和第三方用的接口,Token 更方便。两种方案不是非此即彼,很多系统是 Session 管网页登录、Token 管开放接口。

面试官追问

追问 1JWT 里能放用户手机号吗?
参考回答

别放。JWT 的 payload 只是 base64url 编码,复制到 jwt.io 就能看到原文,签名只保证内容没被改,不保证别人看不到。只放用户 id、角色、过期时间这类必要字段。

追问 2用户改了密码,之前签发的 JWT 怎么让它失效?
参考回答

JWT 本身做不到,得加点状态:用户表存一个 tokenVersion,签发时写进 token,校验时对比,改密码就把版本号加一;或者把要作废的 jti 放进 Redis 黑名单直到它过期。

追问 3Token 存 localStorage 还是 Cookie?
参考回答

localStorage 怕 XSS,脚本一跑就能读走;HttpOnly 的 Cookie 脚本读不到,但会自动带上,要防 CSRF,配 SameSite=Lax 基本够用。我更倾向 HttpOnly 加 Secure 加 SameSite 的 Cookie。

追问 4服务从一台扩到三台,用 Session 的登录老是掉,怎么办?
参考回答

Session 存在各自进程内存里,请求分到别的机器就查不到。把 Session 存到 Redis,比如 express-session 配 connect-redis,三台机器读同一份。

追问 5用了 JWT 是不是就不用查数据库了?
参考回答

验身份可以不查,但权限别全信 token 里的角色。用户被封禁或者降权后,旧 token 里的角色还是老的,敏感操作要再查一次当前状态。

# Session

30 秒速记

  • Session = 服务端给每个用户建一份档案,浏览器只拿一个编号(session id),下次来凭编号查档案
  • 编号一般放 Cookie 自动带上;Cookie 是载体,Session 是服务端的存储,两者配合不是二选一
  • session id 要随机不可猜,登录成功后要换一个新的,防会话固定攻击
  • 默认存进程内存,重启就丢、多实例不共享 → 线上存 Redis
  • 「不能跨域」说的是 Cookie 受域名限制:子域共享靠 Domain,跨站要 credentials + SameSite=None; Secure + 后端允许凭证

Session 就是服务端给每个登录用户建的一份档案,浏览器手里只拿一个编号,每次请求带着编号来,服务端按编号把档案翻出来。 编号通常放在 Cookie 里,所以 Cookie 是载体、Session 是服务端那份数据,两者是配合关系。好处是用户信息不出服务器,想让谁下线直接删档案。坑主要在存储:默认存进程内存,服务一重启或者扩成多实例,档案就找不到了,所以线上都存 Redis。常说的「Session 不能跨域」,本质是装编号的 Cookie 有域名限制,配好 CORS 凭证和 SameSite 是能带过去的。

Session 是一种记录客户状态的机制,不同的是 Cookie 保存在客户端浏览器中,而 Session 保存在服务器上的进程中。

客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上,这就是 Session。客户端浏览器再次访问时只需要从该 Session 中查找该客户的状态就可以了。

如果说 Cookie 机制是通过检查客户身上的“通行证”来确定客户身份的话,那么 Session 机制就是通过检查服务器上的“客户明细表”来确认客户身份。

Session 相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。

Session 不能跨域

面试官追问

追问 1把完整用户信息放进 Cookie,服务端什么都不存,这算 Session 吗?
参考回答

不算,这是纯 Cookie 方案。没签名的话用户改一下 Cookie 就能冒充别人。Session 的要点是数据在服务端,客户端只有一个查档案用的随机 id。

追问 2登录成功后为什么要重新生成 session id?
参考回答

防会话固定攻击:攻击者先拿到一个 id 塞给你,你用它登录后,他手里的 id 也成了登录态。express-session 里登录成功调一次 req.session.regenerate()。

追问 3运营后台在 admin.a.com,接口在 api.a.com,请求总是拿不到 Session,怎么办?
参考回答

前端请求要带 credentials: 'include',后端返回 Access-Control-Allow-Credentials: true,并且 Allow-Origin 写具体域名不能写 *。两个子域同站,Cookie 设 Domain=.a.com 就能共享。

追问 4管理员要求能立刻把某个用户踢下线,Session 怎么做?
参考回答

在 Redis 里按用户 id 维护一个他的 session id 列表,踢人时把这些 Session 全删了,用户下次请求就查不到档案,自然掉线。

追问 5用户量很大,Session 存储会不会扛不住?
参考回答

一个 Session 一般就几百字节,百万在线也就几百 MB,Redis 完全扛得住。关键是设置合理的过期时间,别把大对象塞进 Session,存个用户 id 就够了,详细信息用时再查。

# Session 与 Cookie 的区别

30 秒速记

  • 存哪:Cookie 在浏览器,Session 在服务端;Session 通常靠一个 Cookie 存 session id
  • 安全:Cookie 内容用户能看能改,敏感状态放 Session;Cookie 要配 HttpOnly、Secure、SameSite
  • 成本:Session 占服务端存储,访问量大要放 Redis 并设过期;Cookie 每个请求都带,太大浪费带宽
  • 限制:单个 Cookie 约 4KB;老标准说单站 20 个,现在主流浏览器单域名能存一百多个,但别往这上面靠
  • 生命周期:Cookie 靠 Expires / Max-Age,Session 靠服务端过期时间,两边要对齐

Cookie 存在浏览器,Session 存在服务端,而且 Session 一般就是靠一个 Cookie 来存它的 id。 因为 Cookie 在用户手里,能看能改,所以用户 id、权限这类决定身份的东西不能明文放 Cookie,要么放 Session,要么签名。Session 的代价是服务端要存,访问一大占内存,所以都放 Redis 并设过期时间。Cookie 的限制是单个大约 4KB,而且每个请求都会带上,塞多了每次请求都在浪费流量。我的习惯是 Cookie 里只放一个 session id,配好 HttpOnly 和 SameSite。

  • Cookie 数据存放在客户的浏览器上,Session 数据放在服务器上的进程中。
  • Cookie 不是很安全,别人可以分析存放在本地的 Cookie 并进行 Cookie 欺骗 考虑到安全应当使用 Session。
  • Session 会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
  • 单个 Cookie 保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个 Cookie。

← 操作数据库Cookie、Session、Token、JWT →

fe